package pt.isel.pdm.ouryamba;

import java.util.List;
import java.util.concurrent.atomic.AtomicBoolean;
import winterwell.jtwitter.Twitter.Status;
import winterwell.jtwitter.TwitterException;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;

/**
 * This is the service responsible for upload all the uncommitted status from the database to the server.
 * */
public class StatusUploadService extends Service implements Runnable
{
	private AtomicBoolean hasWork;
	private General app;
	private Thread worker_thread;
	public String ID;
	private final String WORKER_THREAD_NAME = ID + "_worker_thread";
	private final Object waitingForWork = new Object();
	
	
//Service methods
	
	/**
	 * Since this is a started service, the is no object to bind.
	 * */
	@Override
	public IBinder onBind(Intent arg0) 
	{
		return null;
	}

	/**
	 * Starts the background worker thread and stores a reference for the Application instance. 
	 * */
	@Override
	public void onCreate()
	{
		super.onCreate();
		ID = StatusUploadService.class.getName();
		hasWork = new AtomicBoolean(false);
		app = (General) getApplication();
		worker_thread = new Thread(this, WORKER_THREAD_NAME);
		worker_thread.start();
	}	

	/**
	 * Inform the worker thread that has work to do (status on the database to upload).
	 * 
	 * @return The flag START_NOT_STICKY which means the service should not be restarted after
	 * Android killed the service for memory usage.
	 * */
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) 
	{
		hasWork.compareAndSet(false, true);
		synchronized (waitingForWork)
		{
			waitingForWork.notify();
		}
		return START_NOT_STICKY;
	}

	/**
	 * Interrupts the worker thread and reference it to null to help the GC.
	 * */
	@Override
	public void onDestroy()
	{
		worker_thread.interrupt();
		worker_thread = null;
		super.onDestroy();
	}
	
//Runnable methods
	
	/**
	 * Upload the statuses waiting for being uploaded. </br>
	 * 
	 * When the thread don't have work to do (all status were sent) or don't have network connectivity,
	 * it waits until there are conditions to continue work.</br>
	 * 
	 * Fetch all the status from the database and for each of them, upload to the server and remove from the database.
	 * Performs a sleep between each status upload because if too many status were sent to quickly the server will ban me
	 * from upload more.
	 * 
	 * @see General#dbSelectByCommittedValue(boolean)
	 * @see General#hasNetworkConnection()
	 * @see General#getTwitter()
	 * @see General#log(String)
	 * @see General#dbDelete(Status, boolean)
	 * @see General#statusUploadSuccess()
	 * @see General#statusUploadFailed()
	 * @see General#logException(Exception)
	 * */
	@Override
	public void run() 
	{
		try
		{
			while(true)
			{
				if(hasWork.get())
				{
					List<Status> list = app.dbSelectByCommittedValue(false);
					int index = 0;
					for(Status status : list)
					{
						if(!app.hasNetworkConnection())
						{
							break;
						}
						try
						{
							app.getTwitter().updateStatus(status.text);
							app.log("StatusUpdloadService.worker_thread.run(): Status sent.");
							app.dbDelete(status, false);
							app.statusUploadSuccess();
							if(index++ < list.size())
							{
								Thread.sleep(300);
							}
						}catch(Exception e)
						{
							app.statusUploadFailed();
							break;
						}
					}
					if(index == list.size())
					{
						hasWork.set(false);
					}
				}
				else
				{
					synchronized (waitingForWork) 
					{
						app.log("StatusUpdloadService.worker_thread.run(): Going to wait for work.");
						waitingForWork.wait();
						app.log("StatusUpdloadService.worker_thread.run(): Waking up for work.");
					}
				}
				if(!app.hasNetworkConnection())
				{
					app.log("StatusUpdloadService.worker_thread.run(): Going to wait for network.");
					synchronized (app.waiterForNetworkLock)
					{
						app.waiterForNetworkLock.wait();
					}
					app.log("StatusUpdloadService.worker_thread.run(): Waking up for network.");
				}
			} //END WHILE
		}
		catch (InterruptedException e)
		{
			app.log("StatusUpdloadService.worker_thread.run(): Thread interrupted.");
		}
		catch (TwitterException e)
		{
			app.log("StatusUpdloadService.worker_thread.run(): Twitter thrown an exception.");
			app.logException(e);
		}
		catch (Exception e)
		{
			app.log("StatusUpdloadService.worker_thread.run(): Exception thrown.");
			app.logException(e);
		}
	}
	
}
